/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import i18n from 'i18next';

import {
  CommandDialog,
  DocumentEvents,
  DocumentObject,
  Icon,
  ParameterObjectType,
  Types,
  useUnit,
} from '@amcax/base';
import { CommandFormWrapper } from '@app-base/common/components/command-form';
import { CommandFormFooter } from '@app-base/common/components/command-form/footer';
import { InputWithFormat } from '@app-base/common/components/command-form/InputWithFormat';
import { getUnitForExpression } from '@app-base/common/components/command-form/utils';
import { MouseActionInput } from '@app-base/common/components/pick-input/mouse-action-input';
import { unitManager, userEvents } from '@app-base/module';
import { LinkedParameterInput } from '@app-cad/common/components/command-form/LinkedParameterInput';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useParameterLinkedTable } from '@app-cad/common/hooks/useParameterLinkedTable';
import { wsApi } from '@app-cad/server';
import { CurvedBaseCommand, EditableCmdDialogParams } from '@app-cad/types';
import { Radio } from 'antd';
import { useEffect, useMemo, useState } from 'react';

function ParameterObjectCommand({
  title,
  onClose,
  props,
}: EditableCmdDialogParams) {
  const linkedTable = useParameterLinkedTable(props?.dxid);

  const [isLoading, setIsLoading] = useState(false);
  const unitConfig = useUnit();

  const [parent, setParent] = useState<DocumentObject>();
  const [type, setType] = useState<ParameterObjectType>(
    ParameterObjectType.Length,
  );

  const [expr, setExpr] = useState<string | number>(0);

  const [designTableOpen, setDesignTableOpen] = useState(false);

  const unit = useMemo(() => {
    if (typeof props?.params?.expr === 'string') {
      return props?.params?.unit;
    }

    if (type === ParameterObjectType.Length) {
      return unitConfig.lengthUnit;
    }

    if (type === ParameterObjectType.Angle) {
      return unitConfig.angleUnit;
    }

    return null;
  }, [type, unitConfig]);

  const editDxid = (props as unknown as DocumentObject)?.dxid;

  useEffect(() => {
    if (props == null) {
      return;
    }

    const paramsExpr = props.params.expr;

    setExpr(
      typeof paramsExpr === 'string'
        ? paramsExpr
        : paramsExpr *
            (unitManager.getUnitParams(props.params.unit)?.multiple ?? 1),
    );
    setType(props.params.type);
  }, [editDxid]);

  const onSubmit = async () => {
    const isExpression = typeof expr === 'string';
    // Input抛出的始终以mm为单位
    const exprParam =
      isExpression || unit == null
        ? expr
        : expr / (unitManager.getUnitParams(unit)?.multiple ?? 1);

    const unitParam = isExpression ? getUnitForExpression(type).name : unit;

    setIsLoading(true);

    try {
      if (props == null) {
        await wsApi.createParameterObject(
          {
            type,
            expr: exprParam,
            unit: unitParam,
          },
          parent?.dxid,
        );
      } else {
        await wsApi.editParameterObject(editDxid, {
          expr: exprParam,
          unit: unitParam,
        });
      }
    } finally {
      setIsLoading(false);
    }
    onClose();
  };

  const onObjectSelected = (selectedObject: DocumentObject) => {
    if (selectedObject.type === Types.PARAMETER_SET) {
      setParent(selectedObject);
    }
  };

  useEffect(() => {
    userEvents.on(DocumentEvents.SELECT_TREE_OBJECT, onObjectSelected);

    return () => {
      userEvents.off(DocumentEvents.SELECT_TREE_OBJECT, onObjectSelected);
    };
  }, []);

  useCommand('parameter-set', {
    onClose,
    finishDraw: onSubmit,
  });

  return (
    <CommandDialog
      onClose={onClose}
      title={title}
      placement='topLeft'
    >
      <CommandFormWrapper>
        {props == null && (
          <MouseActionInput
            active
            placeholder='请选择父数据集（可选）'
          >
            <div className='flex items-center'>
              {parent?.label}
              {parent != null && (
                <Icon
                  className='ml-auto block'
                  tabIndex={0}
                  name='commons/close'
                  onClick={() => {
                    setParent(null);
                  }}
                />
              )}
            </div>
          </MouseActionInput>
        )}
        <Radio.Group
          disabled={props != null}
          onChange={(e) => {
            setType(e.target.value);
            setExpr(0);
          }}
          value={type}
        >
          {[
            {
              val: ParameterObjectType.Length,
              label: '长度',
            },
            {
              val: ParameterObjectType.Angle,
              label: '角度',
            },
            {
              val: ParameterObjectType.Real,
              label: '实数',
            },
            {
              val: ParameterObjectType.Integer,
              label: '整数',
            },
          ].map(({ val, label }) => {
            return <Radio value={val}>{label}</Radio>;
          })}
        </Radio.Group>
        {linkedTable ? (
          <LinkedParameterInput
            type={type}
            exprId={props?.dxid}
            expr={expr}
            setExpr={setExpr}
            open={designTableOpen}
            setOpen={setDesignTableOpen}
            tableId={linkedTable.dxid}
            table={linkedTable.table}
          />
        ) : (
          <InputWithFormat
            className='w-full'
            inputType={type}
            value={expr}
            onChange={setExpr}
          />
        )}

        <CommandFormFooter
          isSubmitLoading={isLoading}
          onClose={onClose}
          onSubmit={onSubmit}
        />
      </CommandFormWrapper>
    </CommandDialog>
  );
}

export const cmdParameterObject: CurvedBaseCommand = {
  id: 'CmdParameterObject',
  label: '参数',
  icon: 'commands/common/parameters',
  create: (label, onClose, props) => (
    <ParameterObjectCommand
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
